<?php

namespace Saber\Helper\Http;


use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Utils;

class BaseHttp
{

    protected $baseUri = '';

    /**
     * @var Client|null
     */
    protected ?Client $client = null;

    protected array $options = [];

    /**
     * @var array
     */
    protected static array $defaults = [
        'verify'          => false ,
        'connect_timeout' => 5 ,
        'curl'            => [
            CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4 ,
        ] ,
    ];

    public function __construct () {

        $this->client = new Client(['base_uri' => $this->baseUri]);
    }

    /**
     * 2024-04-22T11:45:25.666+08:00
     * GET 请求
     *
     * @param string $url
     * @param array  $query
     *
     * @return array|mixed|object|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function httpGet (string $url , array $query = []) : Result {

        //驱动

        return $this->request ($url , 'GET' , ['query' => $query]);
    }

    /**
     * post request.
     *
     * @param string $url
     * @param array  $data
     * @param array  $query
     *
     * @return array|mixed|object|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function httpPost (string $url , array $data = [] , array $query = []) : Result {

        return $this->request ($url , 'POST' , ['form_params' => $data , 'query' => $query]);
    }

    /**
     * JSON request.
     *
     * @param string $url
     * @param array  $data
     * @param array  $query
     *
     * @return Result
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function httpPostJson (string $url , array $data = [] , array $query = []) : Result {

        return $this->request ($url , 'POST' , ['query' => $query , 'json' => $data]);
    }

    /**
     * 传文件
     *
     * @param string $url
     * @param array  $multipart
     * @param array  $query
     * @param array  $headers
     *
     * @return Result
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function httpPostFile (
        string $url , array $multipart = [] , array $query = [] , array $headers = []) : Result {

        return $this->request ($url , 'POST' , ['query' => $query , 'multipart' => $multipart , 'heard' => $headers]);
    }

    protected function getOptions () : array {

        return $this->options;
    }

    /**
     * @param string $url
     * @param string $method
     * @param array  $options
     *
     * @return Result
     * @throws GuzzleException
     */
    protected function request (string $url , string $method = 'GET' , array $options = []) : Result {

        $options = $this->fixJsonIssue ($options);
        if ( property_exists ($this , 'baseUri') && !is_null ($this->baseUri) ) {
            $options['base_uri'] = $this->baseUri;
        }

        $handler = $this->getHandlerStack ();
        if ( !empty($handler) ) {
            $options['handler'] = $handler;
        }

        //结果
        $options  = array_merge (self::$defaults , $options);
        $response = $this->client->request (strtoupper ($method) , $url , $options);
        $response->getBody ()->rewind ();

        return new Result($response->getBody ()->getContents ());
    }

    /**
     * @param array $options
     *
     * @return array
     */
    protected function fixJsonIssue (array $options) : array {

        if ( isset($options['json']) && is_array ($options['json']) ) {
            $options['headers'] = array_merge ($options['headers'] ?? [] , ['Content-Type' => 'application/json']);
            if ( empty($options['json']) ) {
                $options['body'] = Utils::jsonEncode ($options['json'] , JSON_FORCE_OBJECT);
            } else {
                $options['body'] = Utils::jsonEncode ($options['json'] , JSON_UNESCAPED_UNICODE);
            }
            unset($options['json']);
        }

        return $options;
    }

    protected function getHandlerStack () {

        return null;
    }

}
